package com.hobbo.ijkbus.struct;

import android.text.TextUtils;

import com.hobbo.ijkbus.struct.exception.FunctionException;
import com.hobbo.ijkbus.struct.function.FunctionNoParamNoResult;
import com.hobbo.ijkbus.struct.function.FunctionWithParamAndResult;
import com.hobbo.ijkbus.struct.function.FunctionWithParamOnly;
import com.hobbo.ijkbus.struct.function.FunctionWithResultOnly;

import java.util.HashMap;

/**
 * @author zsc
 * @create 2019/4/12 0012
 * @Describe
 */
public class FunctionManager {

    public static FunctionManager getInstance() {
        return Holder.Instances;
    }

    private FunctionManager() {
        mNoParamNoResult = new HashMap<>();
        mParamOnly = new HashMap<>();
        mResultOnly = new HashMap<>();
        mParamAndResult = new HashMap<>();
    }

    private static class Holder {
        private static FunctionManager Instances = new FunctionManager();
    }


    private HashMap<String, FunctionNoParamNoResult> mNoParamNoResult;
    private HashMap<String, FunctionWithParamOnly> mParamOnly;
    private HashMap<String, FunctionWithResultOnly> mResultOnly;
    private HashMap<String, FunctionWithParamAndResult> mParamAndResult;


    public FunctionManager addFunction(FunctionNoParamNoResult function) {
        mNoParamNoResult.put(function.getFunctionName(), function);
        return this;
    }

    public FunctionManager addFunction(FunctionWithResultOnly function) {
        mResultOnly.put(function.getFunctionName(), function);
        return this;
    }


    public FunctionManager addFunction(FunctionWithParamOnly function) {
        mParamOnly.put(function.getFunctionName(), function);
        return this;
    }

    public FunctionManager addFunction(FunctionWithParamAndResult function) {
        mParamAndResult.put(function.getFunctionName(), function);
        return this;
    }


    public void invokeFunction(String functionName) {
        if (TextUtils.isEmpty(functionName))
            return;
        if (mNoParamNoResult != null) {
            FunctionNoParamNoResult functionNoParamNoResult = mNoParamNoResult.get(functionName);
            if (functionNoParamNoResult != null) {
                functionNoParamNoResult.function();
            } else {
                try {
                    throw new FunctionException("has no this function");
                } catch (FunctionException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    public <Result> Result invokeFunction(String functionName, Class<Result> clazz) {
        if (TextUtils.isEmpty(functionName))
            return null;

        if (mResultOnly != null) {
            FunctionWithResultOnly functionWithResultOnly = mResultOnly.get(functionName);
            if (functionWithResultOnly != null) {
                if (clazz != null) {
                    return clazz.cast(functionWithResultOnly.function());
                } else {
                    return (Result) functionWithResultOnly.function();
                }
            } else {
                try {
                    throw new FunctionException("has no this function");
                } catch (FunctionException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }


    public <Param> void invokeFunction(String functionName, Param param) {
        if (TextUtils.isEmpty(functionName))
            return;
        if (mParamOnly != null) {
            FunctionWithParamOnly functionWithParamOnly = mParamOnly.get(functionName);
            if (functionWithParamOnly != null) {
                functionWithParamOnly.function(param);
            } else {
                try {
                    throw new FunctionException("has no this function");
                } catch (FunctionException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    public <Param, Result> Result invokeFunction(String functionName, Param param, Class<Result> clazz) {
        if (TextUtils.isEmpty(functionName)){
            return null;
        }
        if (mParamAndResult != null) {
            FunctionWithParamAndResult functionWithParamAndResult = mParamAndResult.get(functionName);
            if (functionWithParamAndResult != null) {
                if (clazz != null) {
                    return clazz.cast(functionWithParamAndResult.function(param));
                } else {
                    return (Result) functionWithParamAndResult.function(param);
                }
            } else {
                try {
                    throw new FunctionException("has no this function");
                } catch (FunctionException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }


}
